package com.dxy.data.webcloud.gateway.web;

import com.alibaba.fastjson.JSON;
import com.dxy.data.webcloud.gateway.config.DynamicRouteServiceImpl;
import com.dxy.data.webcloud.gateway.domain.GatewayPredicateDefinition;
import com.dxy.data.webcloud.gateway.domain.GatewayRouteDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.*;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.*;

/**
 * @CLassName: RouteController
 * @Author: weixin
 * @Description: TODO
 * @DATE: 2018/11/19 4:50 PM
 * @Version: 1.0
 */
@RestController
@RequestMapping("/route")
public class RouteController {

    private final static Logger logger = LoggerFactory.getLogger(RouteController.class);

    @Autowired
    private DynamicRouteServiceImpl dynamicRouteService;

    @Autowired
    private RouteDefinitionLocator routeDefinitionLocator;

    @Autowired
    private RouteLocator routeLocator;

    @PostMapping("/delete")
    public Mono<ResponseEntity<Object>> delete(@RequestBody String json) {
        String id = JSON.parseObject(json).getString("id");
        return dynamicRouteService.delete(id);
    }

    @PostMapping("/add")
    public String add(@RequestBody GatewayRouteDefinition gatewayRouteDefinition) {
        try {
            RouteDefinition definition = assembleRouteDefinition(gatewayRouteDefinition);
            return this.dynamicRouteService.add(definition);
        } catch (Exception e) {
            logger.debug(e.getMessage());
        }
        return "success";
    }

    @GetMapping("/routes")
    public Mono<List<Map<String, Object>>> all() {
        Mono<Map<String, RouteDefinition>> routeDefs = this.routeDefinitionLocator.getRouteDefinitions().collectMap(RouteDefinition::getId);
        Mono<List<Route>> routes = this.routeLocator.getRoutes().collectList();
        return Mono.zip(routeDefs, routes).map((tuple) -> {
            Map<String, RouteDefinition> defs = (Map)tuple.getT1();
            List<Route> routeList = (List)tuple.getT2();
            List<Map<String, Object>> allRoutes = new ArrayList();
            routeList.forEach((route) -> {
                HashMap<String, Object> r = new HashMap();
                r.put("route_id", route.getId());
                r.put("order", route.getOrder());
                if (defs.containsKey(route.getId())) {
                    r.put("route_definition", defs.get(route.getId()));
                } else {
                    HashMap<String, Object> obj = new HashMap();
                    obj.put("predicate", route.getPredicate().toString());
                    if (!route.getFilters().isEmpty()) {
                        ArrayList<String> filters = new ArrayList();
                        Iterator var6 = route.getFilters().iterator();

                        while(var6.hasNext()) {
                            GatewayFilter filter = (GatewayFilter)var6.next();
                            filters.add(filter.toString());
                        }

                        obj.put("filters", filters);
                    }

                    if (!obj.isEmpty()) {
                        r.put("route_object", obj);
                    }
                }

                allRoutes.add(r);
            });
            return allRoutes;
        });
    }

    private RouteDefinition assembleRouteDefinition(GatewayRouteDefinition gwdefinition) {
        RouteDefinition definition = new RouteDefinition();
        List<PredicateDefinition> pdList=new ArrayList<>();
        definition.setId(gwdefinition.getId());
        List<GatewayPredicateDefinition> gatewayPredicateDefinitionList=gwdefinition.getPredicates();
        for (GatewayPredicateDefinition gpDefinition: gatewayPredicateDefinitionList) {
            PredicateDefinition predicate = new PredicateDefinition();
            predicate.setArgs(gpDefinition.getArgs());
            predicate.setName(gpDefinition.getName());
            pdList.add(predicate);
        }
        definition.setPredicates(pdList);
        URI uri = UriComponentsBuilder.fromHttpUrl(gwdefinition.getUri()).build().toUri();
        definition.setUri(uri);
        return definition;
    }
}
